/**
 * 
 */
package steffens.java.gui.defaultui.general;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;
import javax.swing.JSeparator;

import steffens.java.gui.defaultui.bar.ButtonBar;
//import steffens.java.gui.defaultui.bar.StatusBar;

/**
 * @author Steffen Baumann
 * @version 1.0 
 *
 */
public abstract class DefaultWindow<T extends Window> implements WindowListener, ParentNotifier{

	public static final int CLOSE = JFrame.EXIT_ON_CLOSE;
	public static final int HIDE = JFrame.HIDE_ON_CLOSE;
	public static final int DISPOSE = JFrame.DISPOSE_ON_CLOSE;
	
	private Container bars = new Container();
	
	
	private int closeOption = -1;
	
	private T window = null;
	private ButtonBar buttonBar = null;
	private DefaultBar statusBar = null;
	
	private Component content = null;
	
	private String buttonBarPosition = BorderLayout.SOUTH;
	
	/**
	 * 
	 */
	public DefaultWindow(T window, Dimension size,  boolean centered) {
		this.window = window;
		this.window.addWindowListener(this);
		this.window.setSize(size.width, size.height);
		this.window.setPreferredSize(size);
		setCentered(centered);
	}
	
	public void setCentered(boolean centered){
		if(centered){
			Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
			int x = (screensize.width - window.getSize().width)/2;
			int y = (screensize.height - window.getSize().height)/2;
			window.setLocation(x, y);
		}else{
			window.setLocation(0, 0);
		}
	}
	
	public T getWindow(){
		return window;
	}
	
	/**
	 * @return the closeOption
	 */
	public int getCloseOption() {
		return closeOption;
	}

	/**
	 * @param closeOption the closeOption to set
	 */
	public void setCloseOption(int closeOption) {
		this.closeOption = closeOption;
	}

	/**
	 * @return the buttonBarPosition
	 */
	public String getButtonBarPosition() {
		return buttonBarPosition;
	}

	public void setDefaultCloseOperation(int option) {
		closeOption = option;
	}
	
	public void setButtonBar(ButtonBar buttonBar){
		setButtonBar(buttonBar, BorderLayout.SOUTH);
	}
	
	public void setButtonBar(ButtonBar buttonBar, String buttonBarPosition){
		if(buttonBarPosition == BorderLayout.CENTER) throw new IllegalArgumentException();
		if(buttonBar == null){
			removeButtonBar();
		}else{
			addButtonBar(buttonBar, buttonBarPosition);
		}
	}
	
	private void removeButtonBar(){
		if(this.buttonBar != null){
			window.remove(this.buttonBar.getBarContainer());
			bars.remove(this.buttonBar.getBarContainer());
		}
		validate();
	}
	
	public void setStatusBar(DefaultBar statusBar){
		if(statusBar == null){
			removeStatusBar();
		}else{
			addStatusBar(statusBar);
		}
	}
	
	private void addStatusBar(DefaultBar statusBar) {
		removeStatusBar();
		this.statusBar = statusBar;
		addSouthBars();
		this.statusBar.setParentNotifier(this);
		validate();
	}

	private void removeStatusBar() {
		if(this.statusBar != null){
			bars.remove(this.statusBar.getBarContainer());
		}
		validate();	
	}

	private void addButtonBar(ButtonBar buttonBar, String buttonBarPosition){
		removeButtonBar();
		this.buttonBar = buttonBar;
		if(buttonBarPosition == BorderLayout.SOUTH){
			addSouthBars();
		}else{
			window.add(buttonBar.getBarContainer(), buttonBarPosition);
		}
		this.buttonBarPosition = buttonBarPosition;
		this.buttonBar.setParentNotifier(this);
		validate();
	}

	private void addSouthBars(){
		bars.removeAll();
		bars.setVisible(true);
		bars.setLayout(new BorderLayout());
		if(buttonBar != null && buttonBarPosition == BorderLayout.SOUTH){
			bars.add(buttonBar.getBarContainer(), BorderLayout.NORTH);
		}
		bars.add(new JSeparator(), BorderLayout.CENTER);
		if(statusBar != null){
			bars.add(statusBar.getBarContainer(), BorderLayout.SOUTH);
		}
		window.add(bars, BorderLayout.SOUTH);
	}
	
	public void setContent(Component comp){
		this.content = comp;
		getWindow().add(comp,BorderLayout.CENTER);
		validate();
	}
	
	public Component getContent(){
		return this.content;
	}
	
	private void setToMinimumSize() {
		
		Dimension buttonBarSize = getComponentSize(buttonBar);
		Dimension statusBarSize = getComponentSize(statusBar);
		Dimension contentSize = new Dimension(0,0);
		if(content instanceof SizeRequester){
			contentSize = getComponentSize((SizeRequester)content);
		}
		
		int widthWindow = 0;
		int heightWindow = 0;
		if(buttonBarPosition == BorderLayout.SOUTH || buttonBarPosition == BorderLayout.NORTH){
			widthWindow = getMaxSize(getMaxSize(statusBarSize.width, contentSize.width),
					buttonBarSize.width);
			heightWindow = statusBarSize.height + buttonBarSize.height + contentSize.height;
		}else if(buttonBarPosition == BorderLayout.WEST || buttonBarPosition == BorderLayout.EAST){
			widthWindow = getMaxSize(statusBarSize.width, contentSize.width + buttonBarSize.width);
			heightWindow = getMaxSize(contentSize.height, buttonBarSize.height) + statusBarSize.height;
		}
		
		if(window.isVisible()){
			widthWindow += window.getInsets().right + window.getInsets().left;
			heightWindow += window.getInsets().top + window.getInsets().bottom;
		}
		window.setMinimumSize(new Dimension(widthWindow, heightWindow));
	}

	private Dimension getComponentSize(SizeRequester requester){
		if(requester != null){
			return requester.getMinimumDimension();
		}else{
			return new Dimension(0,0);
		}
	}
	
	private int getMaxSize(int sizeComponent1, int sizeComponent2){
		return Math.max(sizeComponent1, sizeComponent2);
	}
	
	
	public void validate(){
		setToMinimumSize();
		window.validate();
		window.repaint();
	}
	public void setVisible(boolean visible){
		window.setVisible(visible);
		validate();
	}
	public void fireCloseEvent(){
		windowClosed(new WindowEvent(window, CLOSE));
	}
	@Override
	public void windowOpened(WindowEvent e) {
	}
	
	@Override
	public void windowIconified(WindowEvent e) {
	}
	
	@Override
	public void windowDeiconified(WindowEvent e) {
	}
	
	@Override
	public void windowDeactivated(WindowEvent e) {
	}
	
	@Override
	public void windowClosing(WindowEvent e) {
		switch (this.closeOption) {
		case CLOSE:
			if(!(window instanceof Dialog)){
				System.exit(0);
			}
			break;
		case HIDE:
			if(!(window instanceof Dialog)){
				window.setVisible(false);
			}
			break;
		case DISPOSE:
			if(!(window instanceof Dialog)){
				window.dispose();
			}
			break;
		}
	}
	
	@Override
	public void windowClosed(WindowEvent e) {
	}
	
	@Override
	public void windowActivated(WindowEvent e) {
	}
	@Override
	public void notifyParentAboutCahnge() {
		validate();
	}
}
